package iscript.coreFramework.data.datatable
{
	
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;	
	import iscript.coreFramework.data.DataSet;
	import iscript.coreFramework.data.DataTool;
	import iscript.coreFramework.interfaces.IData;
	import iscript.coreFramework.interfaces.IDisposable;
	import iscript.coreFramework.util.CloneHelper;
	import iscript.coreFramework.util.DictionaryUtil;
	import iscript.coreFramework.util.GUID;
    import iscript.coreFramework.data.json.JSON;
	
	public class DataTable extends EventDispatcher  implements IData,IDisposable
	{
		public function DataTable(columns:Vector.<String>)
		{
			setHeadColumn(columns);
			_name = iscript.coreFramework.util.GUID.create();
			DataSet.addDataTable(this);
		}		
		
		/*
		 * 10000条数据 add && filter   208毫秒
		   DataTableView
		  ——————————————————————
		    Head0   Head1
		  ——————————————————————
		    Value   Value
		  ——————————————————————
		*/
		/*
		Format XML
		<FlashDataTable>
		<Column>
		<name>car</name`
		<name>level</name>
		</Column>
		<Row>
		<data car="BMW" level="0"></data>
		<data car="Nissan" level="10"></data>
		</Row>
		</FlashDataTable> 		
		*/
 
		private var _columnNames:Vector.<String> =new Vector.<String>();
		private var _data:Vector.<Dictionary>=new Vector.<Dictionary>();		
		private var _name:String;
		private var _readOnly:Boolean;
		
		public function  set name(value:String):void{
			if(_name== value)return;
		    if(DataSet.IsExistTable(value)) throw new Error("TableName:["+ value +"] "+ DataTableError.ExistDataTable);		
			_name = value;	
		}		
		public function  get name():String{return _name;}
		public function  get readOnly():Boolean{return _readOnly;}
		public function  set readOnly(value:Boolean):void{ _readOnly=value;}
		public function  IsEmtry():Boolean { return this._columnNames.length == 0; }
		 	
	    public function get Columns():Vector.<String> {
		       var sourceColumn:Vector.<String>=new Vector.<String>();
			   for (var item:* in _columnNames) {
			    	sourceColumn.push(_columnNames[item])
			        }
			   return sourceColumn;
	    }   
		   
	    public function get Rows():Vector.<Dictionary> {
		        var sourceRow:Vector.<Dictionary>=new Vector.<Dictionary>();
				for (var item:* in _data) {
					sourceRow.push(_data[item])
				}
				return sourceRow;
		   } 
		   
		public function updateCell(row:int, columnName:String, value:Object):void {
			if(_readOnly)return;
			if(row>RowCount) throw new Error(DataTableError.ExceedRows);
			if(_data[row].hasOwnProperty(columnName)){
				var  updateEvent:DataTableUpdateEvent =   new DataTableUpdateEvent(DataTableEvent.UpdateEvent);				 
			         updateEvent.previousData =  CloneHelper.cloneDictionary(_data[row]);
					 updateEvent.previousColumnValue = _data[row][columnName];
				     _data[row][columnName] = value;
					 updateEvent.changeDataColumnName = columnName;
					 updateEvent.currentData = _data[row];
					 updateEvent.currentColumnValue =  value;
					 updateEvent.currentRowIndex = row;
					 this.dispatchEvent(updateEvent);
			}
		}
		
		public function getRow(rowIndex:int):Dictionary{
		   if(rowIndex>RowCount) throw new Error(DataTableError.ExceedRows);
		   return  CloneHelper.cloneDictionary(_data[rowIndex]);
		}
		
		public function get RowCount():int{
		   return _data.length;	
		}
		
		public function get ColumnCount():int{
		   return _columnNames.length;
		}
			
		public function addRow(rowData:Dictionary):void{
			if(_readOnly)return;
            if(_columnNames.length==0) throw new Error(DataTableError.NoExistColumns);
			for each ( var item:String  in _columnNames){
				 if(!rowData.hasOwnProperty(item)) throw new Error(DataTableError.AddRowError_LackColumn);
			}
			_data.push(rowData); 			
			var  addRowEvent:DataTableAddRowEvent = new DataTableAddRowEvent(DataTableEvent.AddRowEvent);
			addRowEvent.newRowData = CloneHelper.cloneDictionary(rowData);
			this.dispatchEvent(addRowEvent);			
		}
		
		public function removeRowAt(rowIndex:int):void{
			if(_readOnly)return;
			if(rowIndex>RowCount) throw new Error(DataTableError.ExceedRows);			
			var  removeRowEvent:DataTableRemoveRowEvent = new DataTableRemoveRowEvent(DataTableEvent.RemoveRowEvent);
			     removeRowEvent.RemoveRowData = CloneHelper.cloneDictionary(_data[rowIndex]);
			_data.splice(rowIndex,1);
			this.dispatchEvent(removeRowEvent);
		}
		
		/*public function removeMulti(column:String,_data:Array):Vector.<int> {
			   var  indexs:Vector.<int> = new Vector.<int>();
			   var  
			   for (var i:int = 0; i <_data.length; i++) 
			   {
				   for (var j:int = 0; j < _data.length; j++) 
				   {
					   if(_data[i][column]==_data)
				   }
			   }
			}
		*/
		
		public function clear():void{
			if(_readOnly)return;
			_data=new Vector.<Dictionary>();
		}		
		
		public function dispose():void {
			  clear();
			  DataSet.removeDataTable(this);
			}
		
		public function getCell(row:int, columnName:String):*{
			 return getRow(row)[columnName];
			}
	     
		/*public function getCellSource(row:int, columnName:String):* {
			return _data[row][columnName];
		}*/	
			
		/* $data =>
		 * {
			//age: { ">=":5, "<=":10 },
			age:[5,7], 
			name:{"like":"_"}
			 // columnName:{"=":1} 
			}*/
		public function search($data:Object):Vector.<Dictionary> {
			var data:Vector.<Dictionary> = new Vector.<Dictionary>();
			   for (var i:int = 0; i < _data.length; i++) {
				     if (DataTool.filter(DictionaryUtil.formatToObject(_data[i]), $data)){
						 data.push(_data[i]);
						 }
				   }
			return data;
		}
		
		public function searchUnique($data:Object):Dictionary {
			   var data:Vector.<Dictionary> = search($data);
			   if (data.length == 0) return null;
			   return data[0];
			}
		
		
		public function toXML():XML{		    
			/*
			<Column>
			<name>car</name>
			<name>level</name>
			</Column>
			*/
			var columnIndex:int=0;
			var rowIndex:int=0
			var xml:String  ='<DataTable name="'+_name+'">';
			xml+="<Column>";
			for(columnIndex=0;columnIndex<this.ColumnCount;columnIndex++){
				xml+="<name>"+_columnNames[columnIndex]+"</name>";
			}
			xml+="</Column>";
			
			xml+="<Row>";
			for( rowIndex=0;rowIndex<this.RowCount;rowIndex++){
				xml+="<data ";				
				for(columnIndex=0;columnIndex<ColumnCount;columnIndex++){
					xml+=_columnNames[columnIndex]+'="'+ _data[rowIndex][Columns[columnIndex]] +'" '
				}				
				xml+="></data>";
			}
			xml+="</Row>";		

			xml+="</DataTable>";			
			return new XML(xml);
		}
		
		public function toJson():*{
			return   iscript.coreFramework.data.json.JSON.decode(_jsonData());;
		}
		
		public function jsonString():String {
			  return _jsonData();
			}
		
		private  function  _jsonData():String {
			//{name:"xx",rows:[]}
			
			     var result:String = '{"name":'+'"'+this._name+'"';
				     result += ',"rows":[';
					for(var i:int=0;i<_data.length;i++){
						var currentRowJson:String ='{';
						for(var j:int=0;j<_columnNames.length;j++){
							currentRowJson += '"'+_columnNames[j] +'"';
							currentRowJson += ':';
							currentRowJson += '"'+ _data[i][_columnNames[j]] +'"';
							if(j<_columnNames.length-1)currentRowJson += ',';
						}
						currentRowJson +='}';
						if(i<_data.length-1)currentRowJson+=',';					
						result+=currentRowJson;
					}						
		result += ']}';
					return result;
			}
		
		

		private function setHeadColumn(columns:Vector.<String>):void{
			if(ColumnCount>0)  throw  new Error(DataTableError.ReSetColumns);
			if(hasSameItem(columns))  throw  new Error(DataTableError.ExceedRows); 	
			_columnNames = columns;
		}				
		
		private function  hasSameItem(data:Vector.<String>):Boolean{
			var source:Vector.<String>=data;
			var temp:Vector.<String>=new Vector.<String>();
			for(var i:int=0;i<source.length;i++){
				if(temp.indexOf(source[i])==-1){
					temp.push(source[i])  
				}else{
					return true;
				}
			}
			return false;
		}
		
		private function getColumnIndex(columnName:String):int{
		    for(var i:int=0;i<_columnNames.length;i++){
			   if(_columnNames[i] == columnName){
			   return i;
			   }
			}
		    return -1;
		}
		
		private function getColumnNameByIndex(columnIndex:int):String{
			if(columnIndex>ColumnCount) throw new Error(DataTableError.ExceedColumns);	
			return _columnNames[columnIndex];			
		}
		
		public function clone():DataTable {
		//	trace(DataSet.datatableProvider.length,"Dataset length")
			  var  table:DataTable = new DataTable(_columnNames);
			     for (var i:int = 0; i < this._data.length; i++) 
				 {
					 table.addRow(this.getRow(i));
				 }
			   return  table;
			}
		
		/*private function cloneColumn():Vector.<String>{
			var sourceColumn:Vector.<String>=new Vector.<String>();
			for (var item:* in _columnNames) {
				sourceColumn.push(_columnNames[item])
			}
			return sourceColumn;
		}
		
		
		private function cloneRowData():Vector.<Dictionary>{
			var sourceRow:Vector.<Dictionary>=new Vector.<Dictionary>();
			for (var item:* in _data) {
				sourceRow.push(_data[item])
			}
			return sourceRow;
		}*/
		
		
	}
}